#!/bin/sh
#------------------------------------------------------------------------------
# =========                 |
# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
#  \\    /   O peration     |
#   \\  /    A nd           | www.openfoam.com
#    \\/     M anipulation  |
#------------------------------------------------------------------------------
#     Copyright (C) 2012-2016 OpenFOAM Foundation
#     Copyright (C) 2016-2020 OpenCFD Ltd.
#------------------------------------------------------------------------------
# License
#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
#
# Script
#     makeCGAL
#
# Description
#     Build script for CGAL
#
# Note
#     Normally builds against ThirdParty boost and gmp/mpfr when possible.
#     To override this behaviour (and use the system boost and/or gmp/mpfr),
#     simply specify a 'system' version. For example,
#         makeCGAL boost-system gmp-system
#
# ----------------------------------------------
# NO USER-CONFIGURABLE SETTINGS WITHIN THIS FILE
#------------------------------------------------------------------------------
# Dynamic library ending (default is .so)
[ "$(uname -s)" = Darwin ] && EXT_SO=.dylib || EXT_SO=.so

# Short-circuit test for an installation
if [ "$1" = "-test" ]
then
    [ "$#" -eq 3 ] || { echo "${0##*/} -test : needs 2 argument"; exit 1; }
    dir="${2%/}" # <- *_ARCH_PATH
    [ -d "$dir/include" ] || exit 2

# 2020-08-10: Needs reworking for header-only installations!
    if [ -r "$dir/lib$WM_COMPILER_LIB_ARCH/libCGAL$EXT_SO" ]
    then
        echo "    CGAL  include: $dir/include"
        echo "    CGAL  library: $dir/lib$WM_COMPILER_LIB_ARCH"
        # Additional information about boost
        dir="${3%/}" # <- BOOST_ARCH_PATH
        for root in "$dir" /usr
        do
            if [ -d "$root/include/boost" ] \
            && [ -r "$root/lib$WM_COMPILER_LIB_ARCH/libboost_system$EXT_SO" ]
            then
                echo "    boost include: $root/include"
                echo "    boost library: $root/lib$WM_COMPILER_LIB_ARCH"
                break
            fi
        done
        exit 0
    else
        exit 2
    fi
fi
#------------------------------------------------------------------------------
# Run from third-party directory only
cd "${0%/*}" || exit
wmakeCheckPwd "$WM_THIRD_PARTY_DIR" 2>/dev/null || {
    echo "Error (${0##*/}) : not located in \$WM_THIRD_PARTY_DIR"
    echo "    Check your OpenFOAM environment and installation"
    exit 1
}
. etc/tools/ThirdPartyFunctions
#------------------------------------------------------------------------------
unset BOOST_ARCH_PATH CGAL_ARCH_PATH GMP_ARCH_PATH MPFR_ARCH_PATH   # Purge old

# CGAL, boost and gmp/mpfr versions from OpenFOAM etc/config.sh files.
# Get compiler first and let CGAL config override GMP and MPFR
_foamConfig compiler
_foamConfig CGAL

boostPACKAGE=${boost_version:-boost-system}
gmpPACKAGE=${gmp_version:-gmp-system}
mpfrPACKAGE=${mpfr_version:-mpfr-system}
cgalPACKAGE=$cgal_version

#------------------------------------------------------------------------------
usage() {
    exec 1>&2
    while [ "$#" -ge 1 ]; do echo "$1"; shift; done
    cat<<USAGE

usage: ${0##*/} [OPTION] [CGAL-VERSION] [boost-VERSION] [gmp-VERSION] [mpfr-VERSION]
options:
  -gcc          Force use of gcc/g++
  -cmake PATH   Use cmake from the given path
  -no-lib       Configure CGAL for headers-only mode (default OpenFOAM >= 2006)
  -with-lib     Configure CGAL with library
  -toolset=NAME Use named toolset in bootstrap
  -system       Use system versions for boost/gmp/mpfr
  -help

* build CGAL with
      ${cgalPACKAGE:-'unspecified CGAL version'}
      $boostPACKAGE
      $gmpPACKAGE
      $mpfrPACKAGE

Normally builds against ThirdParty boost and gmp/mpfr when possible.
To override this behaviour (and use the system boost and/or gmp/mpfr),
simply specify a 'system' version. For example,
    ${0##*/} boost-system gmp-system

Use gmp-none to disable use of gmp/mpfr (eg, not available)

USAGE
    showDownloadHint BOOST
    showDownloadHint CGAL
    exit 1
}
#------------------------------------------------------------------------------
exportCompiler          # Compiler info for CMake/configure

unset optForce optHeadersOnly optToolset

# Parse options
while [ "$#" -gt 0 ]
do
    case "$1" in
    '') ;;      # Ignore empty
    -h | -help) usage   ;;
    -gcc)       useGcc  ;;
    -force)     optForce=true ;;

    -cmake)
        [ "$#" -ge 2 ] || die "'$1' option requires an argument"
        CMAKE_PATH="${2%%/}"
        shift
        ;;
    -toolset=*)
        optToolset="${1#*=}"
        ;;
    -sys*)
        gmpPACKAGE="gmp-system"
        mpfrPACKAGE="mpfr-system"
        boostPACKAGE="boost-system"
        unset BOOST_ARCH_PATH GMP_ARCH_PATH MPFR_ARCH_PATH
        ;;
    -no-lib)
        optHeadersOnly=true
        ;;
    -with-lib)
        optHeadersOnly=false
        ;;
    gmp-[0-9]* | gmp-system | gmp-none)
        gmpPACKAGE="${1%%/}"
        unset GMP_ARCH_PATH
        ;;
    mpfr-[0-9]* | mpfr-system | mpfr-none)
        mpfrPACKAGE="${1%%/}"
        unset MPFR_ARCH_PATH
        ;;
    boost-[0-9]* | boost_[0-9]* | boost-system )
        boostPACKAGE="${1%%/}"
        unset BOOST_ARCH_PATH
        ;;
    CGAL-[0-9]*)
        cgalPACKAGE="${1%%/}"
        unset CGAL_ARCH_PATH
        ;;
    *)
        die "unknown option/argument: '$1'"
        ;;
    esac
    shift
done

[ -n "$cgalPACKAGE" ] || die "The cgal-VERSION was not specified"

# Nothing to build
if _foamIsNone "$boostPACKAGE"
then
    echo "Using boost-none (skip ThirdParty build of BOOST/CGAL)"
    exit 0
fi
if _foamIsNone "$cgalPACKAGE"
then
    echo "Using cgal-none (skip ThirdParty build of CGAL)"
    exit 0
fi


# For OpenFOAM 1912 and earlier, no predefined default.
# Force headers-only *after* starting with OpenFOAM-v2006
if [ -z "$optHeadersOnly" ] && foamVersion=$(wmake -version 2>/dev/null)
then
    if [ "${foamVersion:-0}" -gt 1912 ]
    then
        optHeadersOnly=true
    fi
fi

# Headers-only - might be able to avoid gmp/mpfr?
## if [ "${optHeadersOnly:-false}" = true ]
## then
##     gmpPACKAGE=none
##     mpfrPACKAGE=none
##     unset GMP_ARCH_PATH MPFR_ARCH_PATH
## fi

#------------------------------------------------------------------------------
#
# Build Boost
# For 64-bit:
# - system is normally built into 'lib64'
# - use Third-Party 'lib64' for consistency.
# Boost 1_62_0 and older normally build into 'lib'.
#
#   BOOST_ARCH_PATH  : installation directory
#   BOOST_SOURCE_DIR : location of the original sources

BOOST_SOURCE_DIR="$sourceBASE/$boostPACKAGE"
: "${BOOST_ARCH_PATH:=$installBASE/$boostPACKAGE}"

boostInc="$BOOST_ARCH_PATH/include"
boostLib="$BOOST_ARCH_PATH/lib$WM_COMPILER_LIB_ARCH"

if _foamIsSystem "$boostPACKAGE"
then
    echo "Using boost-system (skip ThirdParty build of BOOST)"

    # Tagged as 'system' but could actually point to a central location

    if [ -d "$boostInc" ]
    then
        if BOOST_ARCH_PATH=$(cd "$BOOST_ARCH_PATH" 2>/dev/null && pwd -P)
        then
            boostPACKAGE="${BOOST_ARCH_PATH##*/}"
        else
            echo "ERROR: bad path for BOOST_ARCH_PATH"
            echo "stopping build"
            exit 1
        fi

        libdir="$BOOST_ARCH_PATH/lib"
    else
        boostInc="/usr/include"
        boostLib="/usr/lib$WM_COMPILER_LIB_ARCH"
        libdir="/usr/lib"
    fi

    # Use lib/ when lib64/ does not exist
    [ -d "$libdir" -a ! -d "$boostLib" ] && boostLib="$libdir"

elif [ -z "$optForce" ] \
  && [ -f "$boostInc/boost/version.hpp" ]
then
    echo "Using $boostPACKAGE"

    libdir="$BOOST_ARCH_PATH/lib"

    # Use lib when lib64 does not exist
    [ -d "$libdir" -a ! -d "$boostLib" ] && boostLib="$libdir"

else
    echo "Starting build: $boostPACKAGE"
    echo
    # Absolute path for --libdir

    (
        # Write user-config.jam into source directory
        cd "$BOOST_SOURCE_DIR" || exit
        export GIT_DIR="$PWD/.git" # Mask seeing our own git-repo

        # Configuration options:
        unset buildOpt

        # Compiler-specific adjustments
        case "$WM_COMPILER" in
        (Arm*)
            # Toolset for bootstrap
            optToolset="gcc"

            echo "using clang : arm : $(whichCC) ;" > user-config.jam
            echo "using mpi ;" >> user-config.jam

            # Toolset for build
            buildOpt="--user-config=user-config.jam toolset=clang"
            ;;

        (Mingw*)
            # Toolset for bootstrap
            optToolset="gcc"

            echo "using gcc : mingw : $(whichCC) ;" > user-config.jam

            # Toolset for build
            buildOpt="--user-config=user-config.jam toolset=gcc"
            buildOpt="$buildOpt target-os=windows release"
            ;;

        (*)
            # Toolset for bootstrap and build
            if [ -z "$optToolset" ]
            then
                optToolset="$(whichCC)"
                # Base names for gcc-8, clang-9 etc.
                case "$optToolset" in
                (clang*)  optToolset=clang;;
                (gcc*)    optToolset=gcc;;
                esac
            fi
            buildOpt="toolset=$optToolset"
            ;;
        esac

        # End of configuration options
        # ----------------------------

        rm -rf "$BOOST_ARCH_PATH"

        ./bootstrap.sh \
            --prefix="$BOOST_ARCH_PATH" \
            --libdir="$boostLib" \
            --with-libraries=thread \
            --with-libraries=system \
            --with-toolset="$optToolset" \
        && ./b2 $buildOpt -j $WM_NCOMPPROCS install \
        && echo "Built: boost"
    ) || {
        echo "Error building: boost"
        exit 1
    }
fi


# Nothing left to build
if _foamIsSystem "$cgalPACKAGE"
then
    echo "Using cgal-system (skip ThirdParty build of CGAL)"
    exit 0
fi


# Retrieve boost version:
if [ -f "$boostInc/boost/version.hpp" ]
then
    BOOST_VERSION=$(sed -ne 's/^ *# *define *BOOST_VERSION *\([0-9][0-9]*\).*$/\1/p' $boostInc/boost/version.hpp)
else
    echo
    echo "ERROR: boost does not appear to be installed, but is required to build CGAL"
    echo "    Change your settings, or disable entirely (with cgal-system, cgal-none, boost-none)"
    echo "stopping build"
    echo
    exit 1
fi

#------------------------------------------------------------------------------
#
# Build CGAL
# For 64-bit:
# - system is normally built into 'lib64'
# - use Third-Party 'lib64' for consistency.
# CGAL-4.9 normally builds into 'lib64', older versions into 'lib'.
#
#   CGAL_SOURCE_DIR : location of the original sources
#   CGAL_BUILD_DIR  : location of the build
#   CGAL_ARCH_PATH  : installation directory

CGAL_SOURCE_DIR="$sourceBASE/$cgalPACKAGE"
CGAL_BUILD_DIR="$buildBASE/$cgalPACKAGE"
: "${CGAL_ARCH_PATH:=$installBASE/$cgalPACKAGE}"

# gmp/mpfr are installed without compiler name
mpfrBASE="$WM_THIRD_PARTY_DIR/platforms/$WM_ARCH$WM_COMPILER_ARCH"

# Enable/disable gmp/mpfr together
if _foamIsNone "$gmpPACKAGE" || _foamIsNone "$mpfrPACKAGE"
then
    GMP_ARCH_PATH=none
    MPFR_ARCH_PATH=none
elif _foamIsSystem "$gmpPACKAGE" || _foamIsSystem "$mpfrPACKAGE"
then
    # May really be system, but could also by a central installation
    # Ensure everything is accurately recorded. Resolve paths etc.

    if [ -d "$GMP_ARCH_PATH" ]
    then
        if GMP_ARCH_PATH=$(cd "$GMP_ARCH_PATH" 2>/dev/null && pwd -P)
        then
            gmpPACKAGE="${GMP_ARCH_PATH##*/}"
        else
            echo "ERROR: bad path for GMP_ARCH_PATH"
            echo "stopping build"
            exit 1
        fi
    else
        GMP_ARCH_PATH=system
    fi

    if [ -d "$MPFR_ARCH_PATH" ]
    then
        if MPFR_ARCH_PATH=$(cd "$MPFR_ARCH_PATH" 2>/dev/null && pwd -P)
        then
            mpfrPACKAGE="${MPFR_ARCH_PATH##*/}"
        else
            echo "ERROR: bad path for MPFR_ARCH_PATH"
            echo "stopping build"
            exit 1
        fi
    else
        MPFR_ARCH_PATH=system
    fi
else
    GMP_ARCH_PATH="$mpfrBASE/$gmpPACKAGE"
    MPFR_ARCH_PATH="$mpfrBASE/$mpfrPACKAGE"
fi

#------------------------------------------------------------------------------

cat<<SUMMARY
CGAL configuration
------------------
    CGAL    = $cgalPACKAGE
    BOOST   = $boostPACKAGE
    GMP     = $gmpPACKAGE
    MPFR    = $mpfrPACKAGE
------------------
SUMMARY

#
# build information recorded for later use
#
buildInfoFile=$CGAL_ARCH_PATH/share/openfoam-build

recordCGALinfo()
{
    CGAL_VERSION=$(sed -ne 's/^ *# *define *CGAL_VERSION_NR *\([0-9][0-9]*\).*$/\1/p' $CGAL_ARCH_PATH/include/CGAL/version.h 2>/dev/null)

    cat<<BUILD_INFO > $buildInfoFile
# Information from OpenFOAM build on '$(date)'
#
CGAL=${CGAL_ARCH_PATH##*/}
BOOST=${BOOST_ARCH_PATH##*/}
GMP=${GMP_ARCH_PATH##*/}
MPFR=${MPFR_ARCH_PATH##*/}
CGAL_VERSION=$CGAL_VERSION
BOOST_VERSION=$BOOST_VERSION

CGAL_lib=lib$WM_COMPILER_LIB_ARCH
BOOST_lib=lib$WM_COMPILER_LIB_ARCH
CGAL_HEADER_ONLY=${optHeadersOnly:-default}
BUILD_INFO
}


# Compare expected vs what is extracted as KEY=... in text
# $1 = key
# $2 = expected
# $3 = text to extract from
infoValueEq()
{
    local val=$(echo "${3:-unset}" | sed -ne "s/^$1=//p")
    if [ "$2" = "$val" ]
    then
       :
    else
        echo "    $1=$2, previous build had $1='${val:-not-found}'"
        return 1
    fi
}

# Needs build
cgalIsCurrent()
{
    # Only need VAR=... (also avoids embedded '#' that bothers some shells)
    local info=$(sed -n -e '/^[A-Z]/p' $buildInfoFile 2>/dev/null)
    [ -n "$info" ] || return 1

    local libDirName="lib$WM_COMPILER_LIB_ARCH"

    echo "checking information from existing build ..."
    echo "  ${CGAL_ARCH_PATH}"

    infoValueEq CGAL  "${CGAL_ARCH_PATH##*/}"     "$info" || return 1
    infoValueEq BOOST "${BOOST_ARCH_PATH##*/}"    "$info" || return 1
    infoValueEq GMP   "${GMP_ARCH_PATH##*/}"      "$info" || return 1
    infoValueEq MPFR  "${MPFR_ARCH_PATH##*/}"     "$info" || return 1
    infoValueEq BOOST_VERSION "${BOOST_VERSION}"  "$info" || return 1
    infoValueEq CGAL_lib  "$libDirName"           "$info" || return 1
    infoValueEq BOOST_lib "$libDirName"           "$info" || return 1

    return 0
}


if [ -z "$optForce" ] \
 && cgalIsCurrent
then
    echo "    ${CGAL_ARCH_PATH##*/} build appears to be up-to-date - skipping"
    echo
    exit 0
else
(
    # Remove any existing build folder and recreate
    if [ -d "$CGAL_BUILD_DIR" ]
    then
        echo "removing old build directory"
        echo "    $CGAL_BUILD_DIR"
        rm -rf "$CGAL_BUILD_DIR"
    fi
    mkdir -p "$CGAL_BUILD_DIR"

    cd "$CGAL_BUILD_DIR" || exit
    export GIT_DIR="$CGAL_SOURCE_DIR/.git" # Mask seeing our own git-repo

    unset configBoost configGmp configMpfr
    echo "----"
    echo "Configuring $cgalPACKAGE with boost $BOOST_VERSION"
    echo "    Source         : $CGAL_SOURCE_DIR"
    echo "    Build          : $CGAL_BUILD_DIR"
    echo "    Target         : $CGAL_ARCH_PATH"


    # See http://doc.cgal.org/latest/Manual/installation.html
    if _foamIsSystem "$boostPACKAGE"
    then
        # Tagged as 'system' but could actually point to a central location
        if [ -d "$BOOST_ARCH_PATH/include" ]
        then
            echo "    boost          : ${BOOST_ARCH_PATH##*/}"
            configBoost="-DBOOST_ROOT=$BOOST_ARCH_PATH"
        else
            echo "    boost          : system"
        fi

        ## For system - possible that /usr/lib64 not being found?
        ## configBoost="-DBoost_LIBRARY_DIRS=$boostLib"
    elif [ -d "$BOOST_ARCH_PATH" ]
    then
        echo "    boost          : $boostPACKAGE"
        configBoost=$(cat <<CMAKE_OPTIONS
 -DBoost_INCLUDE_DIR=$boostInc
 -DBoost_LIBRARY_DIRS=$boostLib
 -DBoost_THREAD_LIBRARY=$boostLib/libboost_thread$EXT_SO
 -DBoost_THREAD_LIBRARY_RELEASE=$boostLib/libboost_thread$EXT_SO
 -DBoost_SYSTEM_LIBRARY=$boostLib/libboost_system$EXT_SO
 -DBoost_SYSTEM_LIBRARY_RELEASE=$boostLib/libboost_system$EXT_SO
 -DBoost_VERSION=$BOOST_VERSION
CMAKE_OPTIONS
)
    fi

    if _foamIsSystem "$GMP_ARCH_PATH"
    then
        echo "    gmp            : system"
    elif _foamIsNone "$GMP_ARCH_PATH"
    then
        echo "    gmp            : disabled"
        configGmp="-DCGAL_DISABLE_GMP=TRUE"  # Also used for mpfr
    elif [ -d "$GMP_ARCH_PATH" ]
    then
        echo "    gmp            : $gmpPACKAGE"

        for libdir in \
            $GMP_ARCH_PATH/lib$WM_COMPILER_LIB_ARCH \
            $GMP_ARCH_PATH/lib \
        ;
        do
            if [ -f "$libdir/libgmp$EXT_SO" ]
            then
                configGmp=$(cat <<CMAKE_OPTIONS
 -DGMP_INCLUDE_DIR=$GMP_ARCH_PATH/include
 -DGMP_LIBRARIES_DIR=$libdir
 -DGMP_LIBRARIES=$libdir/libgmp$EXT_SO
CMAKE_OPTIONS
)
                break
            fi
        done
    else
        echo "    system         : gmp (did not find $GMP_ARCH_PATH)"
    fi

    if _foamIsSystem "$MPFR_ARCH_PATH"
    then
        echo "    mpfr           : system"
    elif _foamIsNone "$MPFR_ARCH_PATH"
    then
        echo "    mpfr           : disabled"
        configGmp="-DCGAL_DISABLE_GMP=TRUE"  # Also used for mpfr
    elif [ -d "$MPFR_ARCH_PATH" ]
    then
        echo "    mpfr           : $mpfrPACKAGE"

        for libdir in \
            $MPFR_ARCH_PATH/lib$WM_COMPILER_LIB_ARCH \
            $MPFR_ARCH_PATH/lib \
        ;
        do
            if [ -f "$libdir/libmpfr$EXT_SO" ]
            then
                configMpfr=$(cat <<CMAKE_OPTIONS
 -DMPFR_INCLUDE_DIR=$MPFR_ARCH_PATH/include
 -DMPFR_LIBRARIES_DIR=$libdir
 -DMPFR_LIBRARIES=$libdir/libmpfr$EXT_SO
CMAKE_OPTIONS
)
                break
            fi
        done
    else
        echo "    mpfr           : system (did not find $MPFR_ARCH_PATH)"
    fi

    cmake=$(findCMake)

    unset cmakeDefs

    # Compiler-specific adjustments
    case "$WM_COMPILER" in
    (Mingw*)
        cmakeDefs="$cmakeDefs -DCMAKE_SYSTEM_NAME=Windows"
        cmakeDefs="$cmakeDefs -DCMAKE_C_COMPILER=$(wmake -show-c)"
        cmakeDefs="$cmakeDefs -DCMAKE_CXX_COMPILER=$(wmake -show-cxx)"
        ;;
    esac

    # Headers/library decision
    case "$optHeadersOnly" in
    (true | false)
        cmakeDefs="$cmakeDefs -DCGAL_HEADER_ONLY=${optHeadersOnly}"
        ;;
    esac

    # For CGAL < 4.9, for installation into lib64/, not lib/
    # Name only (not path) for CGAL_INSTALL_LIB_DIR
    echo "----"
    set -x
    $cmake \
        -DCMAKE_INSTALL_PREFIX=$CGAL_ARCH_PATH \
        -DCGAL_INSTALL_LIB_DIR=lib$WM_COMPILER_LIB_ARCH \
        -DCMAKE_BUILD_TYPE=Release \
        -DWITH_CGAL_Core=OFF \
        -DWITH_CGAL_ImageIO=OFF \
        -DWITH_CGAL_Qt5=OFF \
        $cmakeDefs \
        $configBoost $configGmp $configMpfr \
        ${WM_QUIET:+-DCMAKE_RULE_MESSAGES=OFF} \
        $CGAL_SOURCE_DIR \
    && set +x \
    && make -j $WM_NCOMPPROCS \
    && make install || exit 1

    echo "----"
    echo "create '\$CGAL_ARCH_PATH/share/files'"
    echo "----"
    mkdir -p $CGAL_ARCH_PATH/share/src
    rm -f $CGAL_ARCH_PATH/share/files

    for i in assertions.cpp io.cpp MP_Float.cpp Random.cpp
    do
        if [ -e "$CGAL_SOURCE_DIR/src/CGAL/$i" ]
        then
            \cp $CGAL_SOURCE_DIR/src/CGAL/$i $CGAL_ARCH_PATH/share/src/
            echo "\${CGAL_ARCH_PATH}/share/src/$i" >> $CGAL_ARCH_PATH/share/files
        fi
    done

    # Record our build-status
    recordCGALinfo

    echo "Done CGAL"
)
fi

#------------------------------------------------------------------------------
